{ This unit is part of Scan Antivirus Present.

    Scan Antivirus Present is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Foobar is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Foobar.  If not, see <http://www.gnu.org/licenses/>.

}
unit umain;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, process, FileUtil, LResources, Forms, Controls, Graphics,
  Dialogs, ComCtrls, ExtCtrls, Buttons, IniPropStorage, Menus, strutils,
  ulegend, uabout, ulicense;

type

{ Threadscan }

Threadscan = class(TThread)
  private
   venable_control : Boolean;
   Vlv_index   : integer;
   Vposbarpro : integer;
   Im_index   : integer;
   txt_index  : string;
   Vtxtbar  : String;
   lanzar   : TProcess;
   vcmd_send: String;
   vcmd_rec : String;
   veicarfile: String;
   vres: String;
   Vhostname : String;
   Vtxt_mes  : String;
   procedure sendfile;
   procedure recfile;
   procedure put_sbar;
   procedure put_barpro;
   procedure put_status_lv;
   procedure messageb;
   procedure endis_controls;
  protected
   procedure Execute; override;
  public
   constructor Create(CreateSuspended : Boolean);

  end;



type

  { Tfmain }

  Tfmain = class(TForm)
    bbtn_scan: TBitBtn;
    bbtn_list: TBitBtn;
    btn_close: TBitBtn;
    bbtn_setting: TBitBtn;
    ilist: TImageList;
    ini_store_conf: TIniPropStorage;
    lanzar: TProcess;
    lv_listpc: TListView;
    MenuItem1: TMenuItem;
    MenuItem2: TMenuItem;
    MenuItem3: TMenuItem;
    MenuItem4: TMenuItem;
    MenuItem5: TMenuItem;
    Panel1: TPanel;
    pbar: TProgressBar;
    pm_export: TPopupMenu;
    pm_help: TPopupMenu;
    sdlg: TSaveDialog;
    sbar: TStatusBar;
    sdir_dlg: TSelectDirectoryDialog;
    tb_main: TToolBar;
    tb_selall: TToolButton;
    tb_revert: TToolButton;
    tb_export: TToolButton;
    ToolButton2: TToolButton;
    ToolButton3: TToolButton;
    tb_reset: TToolButton;
    tb_sumarize: TToolButton;
    tb_legend: TToolButton;
    ToolButton4: TToolButton;
    procedure bbtn_listClick(Sender: TObject);
    procedure bbtn_scanClick(Sender: TObject);
    procedure bbtn_settingClick(Sender: TObject);
    procedure btn_closeClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure MenuItem1Click(Sender: TObject);
    procedure MenuItem2Click(Sender: TObject);
    procedure MenuItem3Click(Sender: TObject);
    procedure MenuItem5Click(Sender: TObject);
    procedure SpeedButton1Click(Sender: TObject);
    procedure tb_selallClick(Sender: TObject);
    procedure tb_revertClick(Sender: TObject);
    procedure tb_resetClick(Sender: TObject);
    procedure tb_sumarizeClick(Sender: TObject);
    procedure tb_legendClick(Sender: TObject);
  private
    procedure parse_strings(Strings : TStringList; Fileparse : String);
    procedure scan_net;
    procedure sel_unsel_all(params : Boolean);
    function  count_check : integer;
    procedure reset_status;
    procedure sumarize;
    procedure export_listv_txt;
    procedure export_listv_html;
    procedure copy_image_list(dir : String);
    function  gethostname : string;
    procedure create_profile;
  public
    workdir : String;
  end;

var
  fmain: Tfmain;
  flegend: Tflegend;
  sumarize_string : TStringList;
  Thscan : Threadscan;
  fabout: Tfabout;
  flicense: Tflicense;

implementation

uses usetting, umethods;

{ Tfmain }


procedure Tfmain.FormCreate(Sender: TObject);
begin
Caption:=Application.Title;
sumarize_string := TStringList.Create;
create_profile;
ini_store_conf.IniFileName:=workdir+'scanav.ini';
end;

procedure Tfmain.FormDestroy(Sender: TObject);
begin
  sumarize_string.Free;
end;

procedure Tfmain.FormShow(Sender: TObject);
begin
end;

procedure Tfmain.MenuItem1Click(Sender: TObject);
begin
  export_listv_txt
end;

procedure Tfmain.MenuItem2Click(Sender: TObject);
begin
 export_listv_html
end;

procedure Tfmain.MenuItem3Click(Sender: TObject);
begin
  flicense:= Tflicense.Create(self);
  flicense.ShowModal;
end;

procedure Tfmain.MenuItem5Click(Sender: TObject);
begin
  fabout:=Tfabout.Create(self);
  fabout.ShowModal;
end;

procedure Tfmain.SpeedButton1Click(Sender: TObject);
begin
end;

procedure Tfmain.tb_selallClick(Sender: TObject);
begin
  sel_unsel_all(true)
end;

procedure Tfmain.tb_revertClick(Sender: TObject);
begin
  sel_unsel_all(false)
end;

procedure Tfmain.tb_resetClick(Sender: TObject);
begin
  reset_status
end;

procedure Tfmain.tb_sumarizeClick(Sender: TObject);
begin
  sumarize
end;

procedure Tfmain.tb_legendClick(Sender: TObject);
begin
   flegend := Tflegend.Create(self);
   flegend.ShowModal;
end;

procedure Tfmain.bbtn_settingClick(Sender: TObject);
begin
  fsettings.ShowModal;
end;

procedure Tfmain.btn_closeClick(Sender: TObject);
begin
  Close
end;

procedure Tfmain.bbtn_scanClick(Sender: TObject);
begin
  pbar.Max:=count_check;
  Thscan := Threadscan.Create(True);
  if Assigned(Thscan.FatalException) then
        raise Thscan.FatalException;
        Thscan.Resume;
end;

procedure Tfmain.bbtn_listClick(Sender: TObject);
begin
  scan_net;
end;

procedure Tfmain.parse_strings(Strings: TStringList; Fileparse : String);
var
  item     : TListItem;
  i        : integer;
  hostname : string;
  StringL  : TStringList;
begin
  StringL := TStringList.Create;
  if Fileparse = 'nmblookup.dat' then
  begin
    parse_nmblookup_unix(Strings,StringL);
    for i:=0 to StringL.Count-1 do
      begin
         hostname:=StringL.ValueFromIndex[i];
         item := lv_listpc.Items.Add;
         item.Caption := hostname;
         item.ImageIndex:= 0;
         item.Checked:=True;
         item.SubItems.Add('None');
      end;
  end;
  if Fileparse = 'nbtscan.dat' then
  begin
   {$IFDEF LINUX} //For Linux
     parse_nbtscan_unix(Strings,StringL);
   {$ENDIF}
   {$IFDEF WIN32} //For MS Windows
     parse_nbtscan_win32(Strings,StringL)
   {$ENDIF}
    for i:=0 to StringL.Count-1 do
      begin
         hostname:=StringL.ValueFromIndex[i];
         item := lv_listpc.Items.Add;
         item.Caption := hostname;
         item.ImageIndex:= 0;
         item.Checked:=True;
         item.SubItems.Add('None');
      end;
  end;
  if Fileparse = 'netview.dat' then
  begin
   parse_netview_win32(Strings,StringL);
   for i:=0 to Strings.Count-1 do
    begin
      hostname:=StringL.ValueFromIndex[i];
      item := lv_listpc.Items.Add;
      item.Caption := hostname;
      item.ImageIndex:= 0;
      item.Checked:=True;
      item.SubItems.Add('None');
    end;
  end;
 {if Fileparse = 'netview.dat' then
  begin
   for i:=0 to Strings.Count-1 do
    begin
     if copy(Strings.Strings[i],1,1) = '\' then
       begin
        hostname:=copy(Strings.Strings[i],3,Length(Strings.Strings[i]));
        hostname:=Copy2Space(hostname);
        item := lv_listpc.Items.Add;
        item.Caption := hostname;
        item.ImageIndex:= 0;
        item.Checked:=True;
        item.SubItems.Add('None');
       end;
   end;
  end;
  if Fileparse = 'nbtscan.dat' then
   begin
     for i:=0 to Strings.Count-1 do
      begin
       if Pos('\',Strings.Strings[i]) >0 then
         begin
          pos_slash:=Pos('\',Strings.Strings[i]);
          hostname:=copy(Strings.Strings[i],pos_slash+1,Length(Strings.Strings[i]));
          hostname:=Copy2Space(hostname);
          item := lv_listpc.Items.Add;
          item.Caption := hostname;
          item.ImageIndex:= 0;
          item.Checked:=True;
          item.SubItems.Add('None');
        end;
      end;
   end;       }
 StringL.Free;
end;

procedure Tfmain.scan_net;
var
  ls_output : TStringList;
  fileparse, filebat : String;
begin
 ls_output := TStringList.Create;
 if not FileExists(workdir+'eicar.com') then
     begin
       ShowMessage('File eicar.com not found, please go to Settings/Wizard');
       Abort;
     end;
 if lv_listpc.Items.Count >=1 then
     lv_listpc.Items.Clear;

 {$IFDEF LINUX} //For Linux
     if ini_store_conf.ReadBoolean('rb_nmblookup_Checked',true) then
     begin
      filebat :='nmblookup.sh' ;
      fileparse:='nmblookup.dat'
     end;
  if ini_store_conf.ReadBoolean('rb_nbtscan_unix_Checked',true) then
     begin
      filebat :='nbtscan.sh' ;
      fileparse:='nbtscan.dat'
     end;
  if FileExists(workdir+fileparse) then
     DeleteFile(workdir+fileparse);
  if not FileExists(workdir+filebat) then
     begin
       ShowMessage('File '+filebat+' not found, please go to Settings/Wizard');
       Abort;
     end;
 {$ENDIF}
 {$IFDEF WIN32} //For MS Windows
  if ini_store_conf.ReadBoolean('rb_netview_Checked',true) then
     begin
      filebat :='netview.bat' ;
      fileparse:='netview.dat'
     end;
  if ini_store_conf.ReadBoolean('rb_nbtscan_Checked',true) then
     begin
      filebat :='nbtscan.bat' ;
      fileparse:='nbtscan.dat'
     end;
  if FileExists(workdir+fileparse) then
     DeleteFile(workdir+fileparse);
  if not FileExists(workdir+filebat) then
     begin
       ShowMessage('File '+filebat+' not found, please go to Settings/Wizard');
       Abort;
     end;
 {$ENDIF}
  if FileExists(workdir+filebat) then
     begin
     {$IFDEF WIN32}
       lanzar.CommandLine:=workdir+filebat;
     {$ENDIF}
     {$IFDEF LINUX}
       lanzar.CommandLine:='sh '+workdir+filebat;
     {$ENDIF}
      sbar.SimpleText:='Scanning...';
      Application.ProcessMessages;
      lanzar.Execute;
      if lanzar.ExitStatus=0 then
         begin
          ls_output.LoadFromFile(workdir+fileparse);
          parse_strings(ls_output,fileparse)
         end
         else
         ShowMessage('Can''t run script '+workdir+filebat);
  sbar.SimpleText:=IntToStr(lv_listpc.Items.Count)+' computers';
  ls_output.Free;
  end;
end;
procedure Tfmain.sel_unsel_all(params: Boolean);
var
  i : integer;
begin
 if lv_listpc.Items.Count >=1 then
   for i:=0 to lv_listpc.Items.Count-1 do
       lv_listpc.Items[i].Checked:=params;
end;

function Tfmain.count_check: integer;
var
  i, sum : integer;
begin
 sum:=0;
 for i:=0 to lv_listpc.Items.Count-1 do
      if lv_listpc.Items[i].Checked then
         sum:=sum+1;
 Result:=sum;
end;

procedure Tfmain.reset_status;
var
  i : integer;
begin
 if lv_listpc.Items.Count >=1 then
   for i:=0 to lv_listpc.Items.Count-1 do
     begin
       lv_listpc.Items[i].Checked:=false;
       lv_listpc.Items[i].ImageIndex:=0;
       lv_listpc.Items[i].SubItems.Text:='None'
     end;
end;

procedure Tfmain.sumarize;
var
  pcuncheck,pcok,pcwarn,pcfail,i : integer;
begin
  sumarize_string.Clear;
  pcuncheck:=0;
  pcok:=0;
  pcwarn:=0;
  pcfail:=0;
  if lv_listpc.Items.Count >=1 then
   for i:=0 to lv_listpc.Items.Count-1 do
     begin
       case lv_listpc.Items[i].ImageIndex of
         0 : pcuncheck:=pcuncheck+1;
         1 : pcok:=pcok+1;
         2 : pcwarn:=pcwarn+1;
         3 : pcfail:=pcfail+1;
       end;
     end;
  sumarize_string.Add('PC Unchecked: '+inttostr(pcuncheck));
  sumarize_string.Add('PC Ok: '+inttostr(pcok));
  sumarize_string.Add('PC Warning: '+inttostr(pcwarn));
  sumarize_string.Add('PC Failed: '+inttostr(pcfail));
  MessageDlg('Sumarize report',sumarize_string.Text,mtInformation,[mbOK],'');
end;

procedure Tfmain.export_listv_txt;
var
  i,leng               : integer;
  content_export       : TStringList;
  rec                  : String;
  fill_space,title_html: String;
begin
 title_html:=Application.Title+' at '+gethostname;
 content_export := TStringList.Create;
 content_export.Add(Application.Title+#13#10);
 content_export.Add('COMPUTER                STATUS');
 fill_space:=DupeString('-',30);
 content_export.Add(fill_space);
 if lv_listpc.Items.Count >=1 then
  begin
   for i:=0 to lv_listpc.Items.Count-1 do
     begin
       leng:=25 - Length(lv_listpc.Items[i].Caption);
       fill_space:=DupeString(' ',leng);
       rec:=lv_listpc.Items[i].Caption+fill_space+Trim(lv_listpc.Items[i].SubItems.Text);
       content_export.Add(rec);
     end;
   fill_space:=DupeString('-',30);
   content_export.Add(fill_space);
   content_export.Add('Powered by: '+title_html);
   content_export.Add('Generated: '+DateToStr(now)+' at '+TimeToStr(now));
   if sdlg.Execute then
      begin
        sdlg.FilterIndex:=0;
        sdlg.DefaultExt:='.txt';
        content_export.SaveToFile(sdlg.FileName);
      end;
  end;
end;

procedure Tfmain.export_listv_html;
var
  header,footer, rec   : string;
  i                    : integer;
  content_export       : TStringList;
  host,status,filename, title_html : String;
begin
  title_html:=Application.Title+' at '+gethostname;
  header:='<html><head><meta content="text/html; charset=ISO-8859-1"'+
          ' http-equiv="content-type"><title>'+title_html+'</title></head><body>'+
          ' <h2>'+Application.Title+'</h2>'+
          ' <table style="text-align: left; width: 50%; height: 50%; margin-left: auto;'+
          ' margin-right: auto;" border="1" cellpadding="0" cellspacing="0">'+
          ' <tbody><tr><td style="vertical-align: middle; width: 1%;'+
          ' text-align: center;"><br></td><th style="vertical-align: top;'+
          ' height: 30%; width: 30%; text-align: center;">COMPUTER<br>'+
          ' </th> <th style="vertical-align: top; width: 30%;'+
          ' text-align: center;">STATUS<br></th></tr><tr>';
  content_export := TStringList.Create;
  content_export.Add(header);
  if lv_listpc.Items.Count >=1 then
   begin
    for i:=0 to lv_listpc.Items.Count-1 do
      begin
       case lv_listpc.Items[i].ImageIndex of
          0 : filename:='pcon.png';
          1 : filename:='pcok.png';
          2 : filename:='pcwarn.png';
          3 : filename:='pcfail.png';
       end;
       host:=lv_listpc.Items[i].Caption;
       status:=Trim(lv_listpc.Items[i].SubItems.Text);
       rec:='<tr><td style="vertical-align: middle; width: 1px; text-align: center;"><img'+
            ' style="width: 24px; height: 24px;" alt=""'+
            ' src="'+filename+'" align="middle"></td>'+
            ' <td style="vertical-align: middle; text-align: center;">&nbsp;'+
            host+'</td><td style="vertical-align: middle; text-align: center;">'+
            status+'</td></tr>';
       content_export.Add(rec);
     end;
  footer:='<tr><td colspan="3" rowspan="1" style="vertical-align: top;">'+
         '<small>Powered by: '+title_html+'</small><br></td></tr>'+
         '<tr><td colspan="3" rowspan="1" style="vertical-align: top;">'+
         '<small>Generated: '+DateToStr(now)+' at '+TimeToStr(now)+'</small><br></td></tr>'+
         ' </tbody></table><br></body></html>';
  content_export.Add(footer);
  if sdir_dlg.Execute then
      begin
        content_export.SaveToFile(sdir_dlg.FileName+'\index.html');
        copy_image_list(sdir_dlg.FileName+'\')
      end;
 end;
end;

procedure Tfmain.copy_image_list(dir : String);
var
 img : TPicture;
 i   : integer;
 imgname : string;
begin
  img := TPicture.Create;
  for i:=0 to ilist.Count-1 do
   begin
     ilist.GetBitmap(i,img.PNG);
     case i of
       0: imgname:='pcon.png';
       1: imgname:='pcok.png';
       2: imgname:='pcwarn.png';
       3: imgname:='pcfail.png';
     end;
     img.SaveToFile(dir+imgname);
   end;
  img.Free;
end;

function Tfmain.gethostname: string;
var
  cmd_output : TStringList;
  lau_cmd    : TProcess;
  hostname   : String;
begin
  hostname:='unknonw';
  cmd_output := TStringList.Create;
  lau_cmd    := TProcess.Create(nil);
  lau_cmd.Options:=[poWaitOnExit,poUsePipes];
  lau_cmd.ShowWindow:=swoHIDE;
  lau_cmd.CommandLine:='hostname';
  lau_cmd.Execute;
  if lau_cmd.ExitStatus = 0 then
    begin
     cmd_output.LoadFromStream(lau_cmd.Output);
     hostname:=cmd_output.ValueFromIndex[0];
    end;
  Result:=hostname;
  cmd_output.Free;
  lau_cmd.Free;
end;

procedure Tfmain.create_profile;
begin
 workdir:=GetAppConfigDir(false);
 if not DirectoryExists(workdir) then
     mkdir(workdir);
end;

{ Threadscan }

procedure Threadscan.sendfile;
var
 i : integer;
 cmd_as : AnsiString;
begin
 Vhostname:='';
 cmd_as:='';
 for i:=0 to fmain.lv_listpc.Items.Count-1 do
   begin
     if fmain.lv_listpc.Items[i].Checked then
        Begin
         Vhostname:=fmain.lv_listpc.Items[i].Caption;
         FmtStr(cmd_as,vcmd_send,[veicarfile,Vhostname,vres]);
         lanzar.CommandLine:=cmd_as;
         Vtxtbar:='Scanning '+Vhostname;
         Synchronize(@put_sbar);
         lanzar.Execute;
         if lanzar.ExitStatus=0 then
            begin
             Vlv_index:=i;
             recfile
            end
         else
           begin
            Vlv_index:=i;
            Im_index:=3;
            txt_index:='Failed';
            Synchronize(@put_status_lv);
           end;
         Vposbarpro:=Vposbarpro+1;
         Synchronize(@put_barpro);
        end;
   end;
   Vposbarpro:=0;
   Synchronize(@put_barpro);
   Vtxtbar:='Done';
   Synchronize(@put_sbar);
end;

procedure Threadscan.recfile;
var
 cmd_as : AnsiString;
begin
 cmd_as:='';
 FmtStr(cmd_as,vcmd_rec,[Vhostname,vres,veicarfile]);
 lanzar.CommandLine:=cmd_as;
 lanzar.Execute;
// Vtxtbar:='Lanzado';
 //Synchronize(@put_sbar);
 if lanzar.ExitStatus=0 then
    begin
     Im_index:=2;
     txt_index:='Warning';
     Synchronize(@put_status_lv);
    end
 else
    begin
      Im_index:=1;
      txt_index:='Ok';
      Synchronize(@put_status_lv);
    end;
end;

procedure Threadscan.put_sbar;
begin
  fmain.sbar.SimpleText:=Vtxtbar;
end;

procedure Threadscan.put_barpro;
begin
  fmain.pbar.Position:=Vposbarpro
end;

procedure Threadscan.put_status_lv;
begin
 fmain.lv_listpc.Items[Vlv_index].SubItems.Text:=txt_index;
 fmain.lv_listpc.Items[Vlv_index].ImageIndex:=Im_index;
 fmain.lv_listpc.Items[Vlv_index].Checked:=False;
end;

procedure Threadscan.messageb;
begin
 ShowMessage(Vtxt_mes);
end;

procedure Threadscan.endis_controls;
begin
  fmain.bbtn_list.Enabled:=venable_control;
  fmain.bbtn_scan.Enabled:=venable_control;
  fmain.tb_selall.Enabled:=venable_control;
  fmain.tb_revert.Enabled:=venable_control;
  fmain.tb_reset.Enabled:=venable_control;
  fmain.tb_sumarize.Enabled:=venable_control;
  fmain.tb_export.Enabled:=venable_control
end;

procedure Threadscan.Execute;
begin
 venable_control:=False;
 Synchronize(@endis_controls);
 sendfile;
 venable_control:=True;
 Synchronize(@endis_controls);
 lanzar.Free;
end;

constructor Threadscan.Create(CreateSuspended: Boolean);
begin
  FreeOnTerminate := True;
  lanzar := TProcess.Create(nil);
  lanzar.Options:=[poWaitOnExit];
  lanzar.ShowWindow:=swoHIDE;
  Vposbarpro:=0;
  vcmd_send:=fmain.ini_store_conf.ReadString('ed_send_eicar_Text','');
  vcmd_rec:=fmain.ini_store_conf.ReadString('ed_rec_eicar_Text','');
  veicarfile:=fmain.ini_store_conf.ReadString('ed_eicar_file_Text','');
  vres:=fmain.ini_store_conf.ReadString('ed_res_Text','');
 inherited Create(CreateSuspended);
end;


initialization
  {$I umain.lrs}

end.
